package com.ctg.platform.core.security.web;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.RegexUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.ctg.payroll2.util.Constants;
import com.ctg.platform.core.SecurityConstants;
import com.ctg.platform.core.security.SpringSecurityManager;

public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource, InitializingBean {
	private String productType;
	public static boolean ischanged = false;
	private SpringSecurityManager springSecurityManager;
	private UrlMatcher urlMatcher;

    private boolean useAntPath = true;
    
    private boolean lowercaseComparisons = true;
    
    /**
     * @param useAntPath the useAntPath to set
     */
    public void setUseAntPath(boolean useAntPath) {
        this.useAntPath = useAntPath;
    }
    
    /**
     * @param lowercaseComparisons
     */
    public void setLowercaseComparisons(boolean lowercaseComparisons) {
        this.lowercaseComparisons = lowercaseComparisons;
    }
    /**
     * 
     */
	public ConfigAttributeDefinition getAttributes(Object filter)
			throws IllegalArgumentException {
		FilterInvocation filterInvocation = (FilterInvocation) filter;
		setProductType(filterInvocation);
        String requestURI = filterInvocation.getRequestUrl();
        if(ischanged){
        	flushAuthorities(filterInvocation);
        }
        Map < String, String > urlAuthorities = this.getUrlAuthorities(filterInvocation);
        
        String grantedAuthorities = null;
        
        if(urlAuthorities.get(requestURI)!=null)
        	grantedAuthorities = urlAuthorities.get(requestURI);
        else{
	        for(Iterator<Map.Entry < String, String >> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
	            Map.Entry < String, String > entry = iter.next();
	            String url = entry.getKey();
	            
	            if(urlMatcher.pathMatchesUrl(url, requestURI)) {
	                grantedAuthorities = entry.getValue();
	                break;
	            }
	        }
        }
        
        if(grantedAuthorities != null) {
            ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
            configAttrEditor.setAsText(grantedAuthorities);
            return (ConfigAttributeDefinition) configAttrEditor.getValue();
        }
        
        throw new AccessDeniedException(SecurityConstants.ACCESS_DENIED_MESSAGE);
	}

	/* (non-Javadoc)
     * @see org.springframework.security.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()
     */
    @SuppressWarnings("unchecked")
	public Collection getConfigAttributeDefinitions() {
		return null;
	}

	@SuppressWarnings("unchecked")
	public boolean supports(Class arg0) {
		return true;
	}

	public void afterPropertiesSet() throws Exception {
		 // default url matcher will be RegexUrlPathMatcher
        this.urlMatcher = new RegexUrlPathMatcher();
        
        if (useAntPath) {  // change the implementation if required
            this.urlMatcher = new AntUrlPathMatcher();
        }
        
        // Only change from the defaults if the attribute has been set
        if ("true".equals(lowercaseComparisons)) {
            if (!this.useAntPath) {
                ((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
            }
        } else if ("false".equals(lowercaseComparisons)) {
            if (this.useAntPath) {
                ((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
            }
        }
	}
	/**
	 * ��servletContext�жs��Ѿ����ȥ��UrlAuthorizates
	 * @param filterInvocation
	 * @return UrlAuthorizatesӳ��
	 */
	@SuppressWarnings("unchecked")
	private Map < String, String > getUrlAuthorities(FilterInvocation filterInvocation) {
        ServletContext servletContext = filterInvocation.getHttpRequest().
        	getSession().getServletContext();
        //��session��ȡ���Ʒ����
        String productType = getProductType();
        //��δ����ǲ����õģ�Ӧ�ô���ʵҵ���л�ȡ��Ʒ����
        return ( Map < String, String > ) servletContext.
        	getAttribute ( SecurityConstants.AUTHORITIES + productType ) ;
    }

	/**
	 * @return ��ȡproductType
	 */
	public String getProductType() {
		return productType;
	}

	/**
	 * @param productType ����productType
	 */
	public void setProductType(FilterInvocation filterInvocation) {
		String productName = (String)filterInvocation.getHttpRequest().getSession().getAttribute(Constants.PRODUCT_NAME);
		if (productName == null) {
			filterInvocation.getHttpRequest().getSession().setAttribute(Constants.PRODUCT_NAME, StringUtils.upperCase(filterInvocation.getHttpRequest().getContextPath().substring(1,filterInvocation.getHttpRequest().getContextPath().length())));
		}
		
		String productType = (String) filterInvocation.getHttpRequest().getSession().getAttribute(Constants.PRODUCT_NAME);
		this.productType = productType;
	}
	/**
	 * ˢ��Ȩ��
	 * @param filterInvocation
	 */
	public void flushAuthorities(FilterInvocation filterInvocation) {
		ServletContext servletContext = filterInvocation.getHttpRequest()
				.getSession().getServletContext();
		springSecurityManager = (SpringSecurityManager) WebApplicationContextUtils
				.getWebApplicationContext(servletContext).getBean(
						"springSecurityManager");
		String productName = this.getProductType();
		List<String> productTypeList = springSecurityManager
				.loadProductTypeList();
		for (String productType : productTypeList) {
			if (productName.equals(productType)) {
				Map<String, String> urlAuthorities = springSecurityManager
				.loadUrlAuthorities(productType);
				servletContext.removeAttribute(SecurityConstants.AUTHORITIES
						+ productType);
				servletContext.setAttribute(SecurityConstants.AUTHORITIES
						+ productType, urlAuthorities);
				break;
			}
		}

		ischanged = false;
	}
}
